#include <iostream>
#include "mem_ptr.h"

class Base
{
public:
    Base() {}
    virtual ~Base() {}
    virtual void print() { std::cout << "Base::print()" << std::endl; }
};

class Person : public Base
{
public:
    Person() {
        printf("Person constructor\n");
    }

    ~Person() {
        printf("Person destructor\n");
    }

    void print() override { std::cout << "Person::print()" << std::endl; }
};

int main() {
    SharedPtr<int> sp1(new int(42));
    std::cout << "sp1 use count: " << sp1.use_count() << std::endl;

    auto rollback = MakeGuard([]()
    {
        printf("hello world");
    });

    {
        SharedPtr<int> sp2 = sp1;
        std::cout << "sp1 and sp2 use count: " << sp1.use_count() << std::endl;

        WeakPtr<int> wp = sp2;
        std::cout << "wp use count: " << wp.use_count() << std::endl;

        SharedPtr<int> sp3 = wp.lock();
        if (sp3) {
            std::cout << "sp3 use count: " << sp3.use_count() << std::endl;
        }
    }

    std::cout << "sp1 use count after sp2 and sp3 go out of scope: " << sp1.use_count() << std::endl;

    WeakPtr<int> wp = sp1;
    sp1.reset();
    std::cout << "wp use count after sp1 go out of scope: " << wp.use_count() << " " << sp1.use_count() << " " << (sp1.get() == nullptr ? "nullptr" : "error") << std::endl;
    if (wp.expired())   
    {
        std::cout << "wp is expired" << std::endl;
    }
    {
        SharedPtr<int[]> sp1(new int[32]);
        auto sp2 = MakeShared<int>(32);
        WeakPtr<int> wp = sp2;
        std::cout << "wp use count: " << wp.use_count() << " " << *(wp.lock()) << std::endl;
    }

    {
        auto sp1 = MakeShared<Person>();
        auto sp2 = sp1.cast<Base>();
        sp1->print();
        sp2->print();
        std::cout << "sp1 use count: " << sp1.use_count() << " " << sp2.use_count() << std::endl;
    }
    // rollback.dismiss();
    return 0;
}